// Sandbox.cpp : Defines the entry point for the console application.
// 
// 
// TODO: add performace calculations
// TODO: add getopts functions for command line input
// TODO: add capability to calculate locations for a file bigger then 4GB
// TODO: add database config file to store parameters 
// TODO: write function to select maximum q (modulo) based on radix and pattern length
// TODO: add program comments to RK functions and textfingerprint class
// TODO: optimize for size and speed
// 

#include "stdafx.h"
#include <stdio.h>
#include <ctime>
#include "TextWindow.h"
#include "TextWindowIterator.h"
#include "TextFingerPrint.h"
#include "TextFingerPrintIterator.h"
#include "TextFPLocationBDB.h"
#include "cProgramOptions.h"


int _tmain(int argc, _TCHAR* argv[])
{
    
    cProgramOptions *opts = new cProgramOptions(argc, argv);
    if (argc <= 2 || opts->isHelp())
    {

    	opts->helpOptions();
        delete opts;
        exit(0);
    }
    else
    {
        try
        {
            opts->verifyOptions();
        }
        catch( char * str)
        {
            printf("**** FATAL ERROR: %s", str); 
            printf("     Press any key to terminate the program ...");
            scanf(str);
            delete opts;
            exit(-1);
        }
        
    }

//std::string file_name("D:/Data/EnglishTexts/KingJamesBible/bible.txt");
//std::string outFileName("C:/Data/RKTestBDB/results.txt");
    string file_name = opts->getTextFile();
    FILE *file_ptr = fopen(file_name.c_str(), "rb");
    string outFileName = opts->getResultsFile();
    FILE *outFile_ptr = fopen(outFileName.c_str(), "a");
    if(file_ptr == NULL) 
    {
        printf("Error: cannot find the file \"%s\"\n", file_name);
    }
    else 
    {  
        // create our burkeley database object & assign parameters
        TextFPLocationBDB bdb(opts->getdbDirectory(), opts->getdbName(), true);
        bdb.setParameters(opts->getRadix(), opts->getModulus(), opts->getWindowSize(), file_name, file_ptr);
        cout << "radix=" << opts->getRadix() << ", modulus=" << opts->getModulus() << ", window-Length=" << opts->getWindowSize();

        /* Create a text window iterator */
        TextWindowIterator text_end = TextWindowIterator::end();
        TextWindowIterator text_it = TextWindowIterator(file_ptr, opts->getWindowSize());


        /* Wrap it around a fingerprint iterator */
        TextFingerPrintIterator fp_it = TextFingerPrintIterator(&text_it, opts->getRadix(), opts->getModulus());
        TextFingerPrintIterator fp_end = TextFingerPrintIterator::end(&text_end);
        
        // Set the number of bytes betwwen each time report
        int mbReport = opts->getMbPerTime() * 1048576;
        int flushCount = 0;

        // Declare variables to track the time
        double myTime, oldTime, timer;
        
        // Set the starting time
        myTime=clock();
        fprintf(outFile_ptr,"\nTextFile = %s, radix=%d,modulus=%l,WinLength=%d\n", 
                            opts->getTextFile(), opts->getRadix(),opts->getModulus(),opts->getWindowSize());
        // declare & initialize variables holding  dereference iterators
//TextFingerPrint& fp = (*fp_it);
//TextWindow &win = (*text_it);
        for(; fp_it != fp_end; fp_it++) {
            TextFingerPrint& fp = (*fp_it);
            TextWindow &win = (*text_it);
//fp = (*fp_it);
//win = (*text_it);
            if (fp.file_position % mbReport == 0)
            {
                oldTime = myTime;
                myTime=clock();
                timer = (myTime-oldTime)/CLOCKS_PER_SEC;
                fprintf(outFile_ptr,"time at %d = %f\n", fp.file_position, timer);
               flushCount++;
                if (flushCount == 10)
                {
                    fflush(outFile_ptr);
//                    bdb.getDBHandle()->sync(0);
                    flushCount = 0;
                }
            }
            bdb.putBDBRec(fp.fingerprint, fp.file_position);
//            HashValue_t true_value = hash_value(win.substring,0,win.length, radix, q);
//            printf("\"%s\": %d=%d\t%d\n", win.substring, fp.fingerprint, true_value, fp.file_position);
        }
        

        // create a vector object we can fill with locations
        std::vector<FilePosition_t> resultVector;
        // we need a variable for the function return value that we will check later
        int returnValue;
        // we also need a variable to tell us how many locations were bad
        int spuriousHits;
        // and a variable to tell us how many locations were actually found
        int numMatches;


        //*********************** test cursor for one pattern
//        std::cout << "SAME LENGTH pattern test::\n";
//        bdb.setPattern("And the");
////        bdb.setPattern("bdb.set");
//        returnValue = bdb.getLocsForPattern(resultVector);
//        printf("The vector contains %d values at these locations:\n", resultVector.size());
////        bdb.showLocsInVector(resultVector);
//        spuriousHits = bdb.getMatchesInTextFile(resultVector);
//        numMatches = resultVector.size();
//        bdb.writeResultsToFile(outFile_ptr, numMatches, spuriousHits);
//        resultVector.erase(resultVector.begin(), resultVector.end());

        //*********************** end of test cursor for one pattern
        
        //*********************** test cursor for range of patterns
//        std::cout << "\n\nSHORTER LENGTH pattern test::\n";
//        bdb.setPattern("And th");
//        returnValue = bdb.getLocsForPattern(resultVector);
//        printf("The vector contains %d values at these locations:\n", resultVector.size());
////        bdb.showLocsInVector(resultVector);
//        spuriousHits = bdb.getMatchesInTextFile(resultVector);
//        numMatches = resultVector.size();
//        bdb.writeResultsToFile(outFile_ptr, numMatches, spuriousHits);
//        resultVector.erase(resultVector.begin(), resultVector.end());
//        //*********************** end of test cursor for range of patterns
//        
        //*********************** test cursor for long pattern
        std::cout << "\n\nLONGER LENGTH pattern test::\n";
        bdb.setPattern("should exercise caution");
                myTime=clock();
        returnValue = bdb.getLocsForPattern(resultVector);
        printf("The vector contains %d values at these locations:\n", resultVector.size());
//        bdb.showLocsInVector(resultVector);
        spuriousHits = bdb.getMatchesInTextFile(resultVector);
        numMatches = resultVector.size();
                timer = ((double)clock()-myTime)/CLOCKS_PER_SEC;
                fprintf(outFile_ptr,"search time = %f\n", timer);
        bdb.writeResultsToFile(outFile_ptr, numMatches, spuriousHits);
        resultVector.erase(resultVector.begin(), resultVector.end());
//    getc(stdin);
        

    }
    
    delete opts;

    fclose(file_ptr);
    fclose(outFile_ptr);
    return 0;
}